home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-16 | 17.0 KB | 596 lines | [TEXT/MPS ] |
- {------------------------------------------------------------------------------
- #
- # Momentum CDEV/INIT
- #
- # Momentum.p - Pascal Source
- #
- # Versions:
- #
- # Components:
- #
- #
- ------------------------------------------------------------------------------}
-
-
- {$S TossManager }
-
-
- UNIT TossManager;
-
-
- INTERFACE
-
-
- USES
- MemTypes, QuickDraw, OSIntf, ToolIntf, SANE, PackIntf, MacPrint, Sound, Traps, GestaltEqu;
-
- CONST
- { indices for 'TossFlags' }
- OnOffFlag = 1; { if 'OnOffFlag' <> 0, then Mo is ON }
- abortFlag = 2;
- SloMoFlag = 3;
- SuperSloMo = 4;
- kGetPtrGestaltSelector = 'gPtr';
- kGestaltCodeRsrcType = 'gCOD';
- kGestaltCodeRsrcID = 128;
-
- TYPE
- LongPt = record
- v: longint;
- h: longint;
- end;
-
- LongRect = record
- top : longint;
- left : longint;
- bottom : longint;
- right : longint;
- end;
-
- TossParamBlk = record
- DeskFrictn : integer; { first 5 fields are settings from the CDEV }
- BouncFrictn : integer;
- GravForce : integer;
- ClockDir : integer;
- GravVector : point; { this value is calculated from force & direction }
- Running : boolean;
- OnlyInFinder : boolean;
- MakeSound : integer; { if zero, don’t do sounds! }
- SndResNum : integer;
- SndChannel : SndChannelPtr;
- TossVelocityV : longint; { pixels/tick*256, calculated on the fly }
- TossVelocityH : longint; { pixels/tick*256, calculated on the fly }
- RegionLoc : point; { region location point }
- ElapsedTicks : longint; { calculated on the fly }
- LongPosition : LongPt;
- NoMoveCycles : integer;
- LastSoundTime : longint;
- MedGraySmoke : Pattern;
- LtGraySmoke : Pattern;
- end;
- TossParamPtr = ^TossParamBlk;
-
- { Units for the param blk:
- DeskFrictn - 1-100
- BouncFrictn - 1-100
- GravForce - 0-100
- GravDirectn - vector containing gravity direction w/out magnitude
- GravVector - pixels/tick (point w/ hor & ver components) to sum with the current velocity. }
-
- ScratchParamBlk = record
- PatchPtr : procPtr;
- OrigActionProc : procPtr;
- LastMouseLoc : point;
- PrevMouseLoc : point;
- LastTime : longint;
- PrevTime : longint;
- KeyMapArea : KeyMap;
- theWorld : rect;
- ZeroPotential : integer;
- end;
- ScratchParamPtr = ^ScratchParamBlk;
-
- PROCEDURE PreMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr);
- PROCEDURE PostMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr);
- FUNCTION TestMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr):boolean;
- FUNCTION IsMoEnabled(TossParms : TossParamPtr):boolean; { checked only once, at the beginning }
- PROCEDURE NewMOPosition (TossParams: TossParamPtr; BoundingRect: Rect);
- PROCEDURE InstallGestaltPtrReference (DataPtr: ptr);
- FUNCTION TossGrayRgn (theRgn : RgnHandle;
- dragResult : Point;
- startPt : Point;
- limitRect : Rect;
- slopRect : Rect;
- axis : INTEGER;
- ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr): Point;
-
-
- IMPLEMENTATION
-
- FUNCTION GetMouseAbort (var abortLoc: point): boolean;
- VAR
- theEvent: EventRecord;
- BEGIN
- { if EventAvail (mDownMask, theEvent) then
- begin
- GetMouseAbort := TRUE;
- abortLoc := theEvent.where;
- FlushEvents(mouseDown+mouseUp, 0);
- end
- else Doesn’t work! }
- GetMouseAbort := FALSE;
- END;
-
- FUNCTION MAX(a, b: real): real;
- BEGIN
- if a>b then
- MAX := a
- else
- MAX := b;
- END;
-
- FUNCTION PtInLongRect (thePt: LongPt; aRect: LongRect): boolean;
- BEGIN
- with thePt, aRect do
- PtInLongRect := ((v>=top)&(v<=bottom)) & ((h>=left)&(h<=right));
- END;
-
- PROCEDURE SetLongPt(VAR thePoint: LongPt; horiz, vert: longint);
- BEGIN
- thePoint.h := horiz;
- thePoint.v := vert;
- END;
-
- PROCEDURE AllocateSndChannel(TossParms: TossParamPtr);
- VAR anErr: OSErr;
- BEGIN
- with TossParms^ do
- begin
- anErr := SndNewChannel(SndChannel, sampledSynth, 0, nil);
- end;
- END;
-
- PROCEDURE PlayBounceSound(TossParams: TossParamPtr);
- CONST kTightSndInterval = 7;
- VAR anErr: OSErr;
- theSound: handle;
- currentTime: longint;
- BEGIN
- with TossParams^ do
- begin
- currentTime := TickCount;
- if (currentTime - LastSoundTime) > kTightSndInterval then { this avoids “machine-gun” ticks }
- begin
- LastSoundTime := currentTime;
- theSound := GetResource('snd ', SndResNum);
- if theSound <> nil then
- begin
- anErr := SndPlay(SndChannel, theSound, true);
- end;
- end;
- end;
- END;
-
- PROCEDURE NewMOPosition (TossParams: TossParamPtr; BoundingRect: Rect);
- { Units: velocity - pixels/tick * 256 (point w/ hor & ver components, multiply to add precision)
- location - quickDraw coordinates (global) }
- VAR
- inBounds : boolean;
- counter : integer;
- VadjVelocity : longint;
- HadjVelocity : longint;
- ProjectedPt : LongPt;
- originalPt : LongPt;
- encloseRect : LongRect;
- frictionDegrade: real;
- speedFactor: longint;
-
- PROCEDURE BounceOnce (VAR OriginalPoint, ProjectedPoint: LongPt;
- VAR HzVelocity, VtVelocity: longint;
- BounceRect: LongRect);
- { 'Reflect' the projected point back off of the wall of 'BounceRect' that it intersects. }
- { Intersection with the rect is returned in 'OriginalPoint', new pt in 'ProjectedPoint'. }
- { Note that the point returned in 'ProjectedPoint' may still be outside of 'BounceRect'. }
- VAR rise, run, intersect: longint;
- bounceDegrade: real;
- soundHdl: handle;
- theErr: OSErr;
- FUNCTION TopBounce: boolean;
- BEGIN
- TopBounce := false;
- if rise = 0 then
- EXIT(TopBounce);
- with BounceRect, OriginalPoint do
- if ProjectedPoint.v <= top then { do we project above the top? }
- begin
- intersect := h + ((top - v)*run) DIV rise; { where do we intersect the top? }
- if (intersect >= left) | (intersect <= right) then { is it within the BoundsRect? }
- begin
- SetLongPt(OriginalPoint, intersect, top); { if so, bounce it off the top! }
- ProjectedPoint.v := top + (top - ProjectedPoint.v);
- VtVelocity := -VtVelocity;
- TopBounce := true;
- end;
- end;
- END;
-
- FUNCTION LeftBounce: boolean;
- BEGIN
- LeftBounce := false;
- if run = 0 then
- EXIT(LeftBounce);
- with BounceRect, OriginalPoint do
- if ProjectedPoint.h <= left then { do we project across the left side? }
- begin
- intersect := v + ((left - h)*rise) DIV run; { where do we intersect the left? }
- if (intersect >= top) | (intersect <= bottom) then { is it within the BoundsRect? }
- begin
- SetLongPt(OriginalPoint, left, intersect); { if so, bounce it off the left side! }
- ProjectedPoint.h := left + (left - ProjectedPoint.h);
- HzVelocity := -HzVelocity;
- LeftBounce := true;
- end;
- end;
- END;
-
- FUNCTION BottomBounce: boolean;
- BEGIN
- BottomBounce := false;
- if rise = 0 then
- EXIT(BottomBounce);
- with BounceRect, OriginalPoint do
- if ProjectedPoint.v >= bottom then { do we project below the bottom? }
- begin
- intersect := h + ((bottom - v)*run) DIV rise; { where do we intersect the bottom? }
- if (intersect >= left) | (intersect <= right) then { is it within the BoundsRect? }
- begin
- SetLongPt(OriginalPoint, intersect, bottom); { if so, bounce it off the bottom! }
- ProjectedPoint.v := bottom + (bottom - ProjectedPoint.v);
- VtVelocity := -VtVelocity;
- BottomBounce := true;
- end;
- end;
- END;
-
- FUNCTION RightBounce: boolean;
- BEGIN
- RightBounce := false;
- if run = 0 then
- EXIT(RightBounce);
- with BounceRect, OriginalPoint do
- if ProjectedPoint.h >= right then { do we project across the right side? }
- begin
- intersect := v + ((right - h)*rise) DIV run; { where do we intersect the right? }
- if (intersect >= top) | (intersect <= bottom) then { is it within the BoundsRect? }
- begin
- SetLongPt(OriginalPoint, right, intersect); { if so, bounce it off the right side! }
- ProjectedPoint.h := right + (right - ProjectedPoint.h);
- HzVelocity := -HzVelocity;
- RightBounce := true;
- end;
- end;
- END;
-
- BEGIN
- with TossParams^ do
- begin
- rise := ProjectedPoint.v - OriginalPoint.v;
- run := ProjectedPoint.h - OriginalPoint.h;
- if NOT BottomBounce then { possibly bounces off bottom }
- if NOT LeftBounce then { possibly bounces off left }
- if NOT RightBounce then { possibly bounces off right }
- if NOT TopBounce then { possibly bounces off top }
- EXIT(BounceOnce);
- if MakeSound <> 0 then PlayBounceSound(TossParams);
- speedFactor := ABS(HzVelocity) + ABS(VtVelocity);
- bounceDegrade := 0.99 - BouncFrictn/200;
- if (speedFactor < 500) then
- bounceDegrade := bounceDegrade*(speedFactor/500);
- HzVelocity := TRUNC(HzVelocity * bounceDegrade);
- VtVelocity := TRUNC(VtVelocity * bounceDegrade);
- end;
- END;
-
-
- BEGIN
- with TossParams^ do begin
- encloseRect.top := BoundingRect.top;
- encloseRect.top := encloseRect.top * 256;
- encloseRect.left := BoundingRect.left;
- encloseRect.left := encloseRect.left * 256;
- encloseRect.bottom := BoundingRect.bottom;
- encloseRect.bottom := encloseRect.bottom * 256;
- encloseRect.right := BoundingRect.right;
- encloseRect.right := encloseRect.right * 256;
- frictionDegrade := (0.995 - DeskFrictn/4000)**ElapsedTicks; { from 0 to 1 }
- HadjVelocity := ROUND((TossVelocityH*frictionDegrade + GravVector.h*ElapsedTicks));
- VadjVelocity := ROUND((TossVelocityV*frictionDegrade + GravVector.v*ElapsedTicks));
-
- ProjectedPt.h := LongPosition.h + HadjVelocity;
- ProjectedPt.v := LongPosition.v + VadjVelocity;
-
- IF (NOT PtInLongRect (ProjectedPt, encloseRect)) THEN begin
- counter := 0;
- originalPt := LongPosition;
- REPEAT
- counter := counter + 1;
- BounceOnce (originalPt, ProjectedPt, HadjVelocity, VadjVelocity, encloseRect);
- inBounds := PtInLongRect (ProjectedPt, encloseRect);
- UNTIL (inBounds OR (counter > 10));
- end;
- TossVelocityH := HadjVelocity;
- TossVelocityV := VadjVelocity;
- LongPosition := ProjectedPt;
- RegionLoc.h := ProjectedPt.h DIV 256;
- RegionLoc.v := ProjectedPt.v DIV 256;
- end; { with }
- END;
-
- PROCEDURE PreMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr);
- BEGIN
- with TossParms^, ScratchPtr^ do
- begin
- { use last - prev to calculate the velocities }
- elapsedTicks := ROUND(MAX(1, LastTime - PrevTime));
- TossVelocityH := LastMouseLoc.h - PrevMouseLoc.h;
- TossVelocityH := ROUND((TossVelocityH*256)/elapsedTicks);
- TossVelocityV := LastMouseLoc.v - PrevMouseLoc.v;
- TossVelocityV := ROUND((TossVelocityV*256)/elapsedTicks);
- LongPosition.h := RegionLoc.h;
- LongPosition.h := LongPosition.h * 256;
- LongPosition.v := RegionLoc.v;
- LongPosition.v := LongPosition.v * 256;
- NoMoveCycles := 0;
- SndChannel := nil;
- LastSoundTime := 0;
- end;
- END;
-
- PROCEDURE PostMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr);
- VAR anErr: OSErr;
- BEGIN
- with TossParms^, ScratchPtr^ do
- begin
- if SndChannel <> nil then
- begin
- anErr := SndDisposeChannel(SndChannel, true);
- SndChannel := nil;
- end;
- end;
- END;
-
- FUNCTION IsMoEnabled(TossParms : TossParamPtr):boolean;
- { checked only once, at the beginning }
- VAR theAppName: str255;
- theFinderName: str255;
- ptr2FndrName,
- ptr2AppName: ptr;
- BEGIN
- with TossParms^ do
- begin
- if Running & OnlyInFinder then
- begin
- ptr2FndrName := ptr($2E0);
- ptr2AppName := ptr($910);
- BlockMove(ptr2FndrName, @theFinderName, 16); { get the name of the Finder }
- BlockMove(ptr2AppName, @theAppName, 32);
- IsMoEnabled := IUEqualString(theFinderName, theAppName) = 0;
- end
- else
- IsMoEnabled := Running;
- end;
- END;
-
- FUNCTION TestMo(ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr):boolean;
- { returns true when it’s time to stop bouncing }
- CONST kStopThreshold = 20;
- TYPE foo = array[0..7] of integer; { added so user can stop by hitting (almost) any key }
- VAR where: point;
- BEGIN
- with ScratchPtr^, TossParms^ do
- begin
- GetKeys(KeyMapArea);
- { if KeyMapArea[1] | GetMouseAbort(where) then } { check the S key for STOP! }
- if (foo(KeyMapArea)[0]<>0) |
- (foo(KeyMapArea)[1]<>0) |
- (foo(KeyMapArea)[2]<>0) |
- (foo(KeyMapArea)[3]<>0) |
- (foo(KeyMapArea)[4]<>0) |
- (foo(KeyMapArea)[5]<>0) |
- (foo(KeyMapArea)[6]<>0) then { check (almost) any key for STOP! }
- begin
- TestMo := true;
- EXIT(TestMo);
- end;
-
- if KeyMapArea[$7C] then { right arrow }
- TossVelocityH := TossVelocityH + 256;
- if KeyMapArea[$7B] then { left arrow }
- TossVelocityH := TossVelocityH - 256;
- if KeyMapArea[$7D] then { down arrow }
- TossVelocityV := TossVelocityV + 256;
- if KeyMapArea[$7E] then { up arrow }
- TossVelocityV := TossVelocityV - 256;
-
- FlushEvents(keyDownMask+keyUpMask+autoKeyMask, 0);
- TestMo := (NoMoveCycles > kStopThreshold);
- end;
- END;
-
- FUNCTION TossGrayRgn (theRgn : RgnHandle;
- dragResult : Point;
- startPt : Point;
- limitRect : Rect;
- slopRect : Rect;
- axis : INTEGER;
- ScratchPtr : ScratchParamPtr;
- TossParms : TossParamPtr): Point;
- { Tail patch for 'DragGrayRgn'. }
- CONST
- kDesiredDelay = 2;
- VAR
- loop : integer;
- currentTk : longint;
- oldPort : grafPtr;
- saveRgn : RgnHandle;
- tLocation : point;
- lastLoc : point;
- bigRect : rect;
- oldPen : PenState;
- grayPatrn : Pattern;
- PauseTicks: longint;
- delH, delV : integer;
-
- BEGIN
- with TossParms^ do begin
- SetPt(RegionLoc, startPt.h + dragResult.h, startPt.v + dragResult.v);
- PreMo(ScratchPtr, TossParms);
- if (ABS(TossVelocityV) < 257) & (ABS(TossVelocityH) < 257) then { note 1 pixel/tick = 256 }
- begin
- TossGrayRgn := dragResult;
- PostMo(ScratchPtr, TossParms);
- EXIT(TossGrayRgn);
- end;
- end;
-
- AllocateSndChannel(TossParms);
- GetPort (oldPort); { set to wMgr port? }
- GetPenState (oldPen);
- saveRgn := NewRgn;
- GetClip (saveRgn);
- SetRect (bigRect, -32000, -32000, 32000, 32000);
- ClipRect (bigRect);
- PenSize (1, 1);
- PenMode (PatXOr);
- GetIndPattern (grayPatrn,0,4);
- PenPat (grayPatrn);
-
- with TossParms^, ScratchPtr^ do
- begin
- bigRect := theRgn^^.rgnBBox;
- slopRect.top := slopRect.top + RegionLoc.v - bigRect.top;
- slopRect.bottom := slopRect.bottom + RegionLoc.v - bigRect.bottom;
- slopRect.left := slopRect.left + RegionLoc.h - bigRect.left;
- slopRect.right := slopRect.right + RegionLoc.h - bigRect.right;
- theWorld := slopRect;
- loop := 1;
- FrameRgn (theRgn); { draw it }
- REPEAT
- loop := loop + 1;
- SetPt(lastLoc, RegionLoc.h, RegionLoc.v);
- PrevTime := LastTime; { update the 'oldest' tick count }
- LastTime := TickCount;
- ElapsedTicks := LastTime - PrevTime;
- NewMOPosition (TossParms, slopRect);
- delH := RegionLoc.h - lastLoc.h;
- delV := RegionLoc.v - lastLoc.v;
- PauseTicks := kDesiredDelay - (TickCount - LastTime);
- if (PauseTicks > 0) then
- Delay(PauseTicks, currentTk);
- if (delH = 0) & (delV = 0) then
- begin
- NoMoveCycles := NoMoveCycles + 1;
- end
- else
- begin
- NoMoveCycles := 0;
- FrameRgn (theRgn); { undraw it @ old position }
- OffsetRgn (theRgn, delH, delV); { move it }
- FrameRgn (theRgn); { draw it @ new position }
- end;
- UNTIL TestMo(ScratchPtr, TossParms);
- FrameRgn (theRgn); { undraw it for final time }
- SetPt(tLocation, RegionLoc.h - startPt.h, RegionLoc.v - startPt.v);
- FlushEvents(keyDownMask+keyUpMask+autoKeyMask, 0);
- end;
-
- SetClip (saveRgn);
- SetPort (oldPort);
- SetPenState (oldPen);
- PostMo(ScratchPtr, TossParms);
- TossGrayRgn := tLocation;
- END;
-
- {######################################################
- Routines that we need to check for availability of Gestalt
- ######################################################}
-
- FUNCTION NumToolboxTraps: Integer;
- begin
- if NGetTrapAddress(_InitGraf, ToolTrap) = NGetTrapAddress($AA6E, ToolTrap) then
- NumToolboxTraps := $200
- else
- NumToolboxTraps := $400;
- end;
-
-
- FUNCTION GetTrapType (theTrap: Integer): TrapType;
- const
- TrapMask = $0800;
- begin
- if (BAND(theTrap, TrapMask) > 0) then
- GetTrapType := ToolTrap
- else
- GetTrapType := OSTrap;
- end;
-
-
- FUNCTION TrapAvailable (theTrap: Integer): Boolean;
- var
- tType: TrapType;
- begin
- tType := GetTrapType(theTrap);
- if tType = ToolTrap then
- begin
- theTrap := BAND(theTrap, $07FF);
- if (theTrap >= NumToolboxTraps) then
- theTrap := _Unimplemented;
- end;
- TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress(_Unimplemented, ToolTrap);
- end;
-
-
- FUNCTION GestaltAvailable: boolean;
- CONST
- GestaltTrap = $A1AD;
- BEGIN
- GestaltAvailable := TrapAvailable (GestaltTrap);
- END;
-
-
-
- {######################################################
- This is the routine you need to call to install the ptr
- ######################################################}
-
- PROCEDURE InstallGestaltPtrReference (DataPtr: ptr);
- { no need to report error, since when we call 'Gestalt' later to get this info it will return an error if we fail here }
- VAR
- codeHdl : handle;
- BEGIN
- IF (GestaltAvailable)
- THEN
- begin
- codeHdl := GetResource (kGestaltCodeRsrcType, kGestaltCodeRsrcID);
- IF (codeHdl <> nil)
- THEN
- begin
- DetachResource (codeHdl);
- IF (NewGestalt (kGetPtrGestaltSelector, codeHdl^) = noErr)
- THEN
- BlockMove (@DataPtr, ptr (ord (codeHdl^) + 10), 4);
- end;
- end;
- END;
-
-
-
-
- END. { unit }